#include "Helper.h"
#include "States.h"
#include <assert.h>
#include <stdio.h>


void State0::read(char c, IAutomat* automat)
{
    if(Helper::isSpace(c)) {
        //do nothing
    } else if(c == '<') {
        shown_row = automat->getRow();
        shown_col = automat->getCol();
        automat->setCurrentState(State11::makeState());
    } else if(c == '/') {
        shown_row = automat->getRow();
        shown_col = automat->getCol();
        automat->setCurrentState(State41::makeState());
    } else if(Helper::isNumerical(c)) {
        automat->putCharForInteger(c);
        shown_row = automat->getRow();
        shown_col = automat->getCol();
        automat->setCurrentState(State2::makeState());
    } else if(Helper::isAlpha(c)) {
        automat->putCharForIdentifier(c);
        shown_row = automat->getRow();
        shown_col = automat->getCol();
        automat->setCurrentState(State3::makeState());
    } else if(Helper::isSign(c)) { //without < and /
        shown_row = automat->getRow();
        shown_col = automat->getCol();
        TType ttype;
        if(c == '+') {
            ttype = TOK_PLUS;
        } else if(c == '-') {
             ttype = TOK_MINUS;
        } else if(c == '/') {
             ttype = TOK_SLASH;
        } else if(c == '*') {
             ttype = TOK_STAR;
        } else if(c == '<') {
             ttype = TOK_ANGLE_BR_OPEN;
        } else if(c == '>') {
             ttype = TOK_ANGLE_BR_CLOSE;
        } else if(c == '=') {
             ttype = TOK_ASSIGN;
        } else if(c == '!') {
             ttype = TOK_EXCL;
        } else if(c == '&') {
             ttype = TOK_AMPERSAND;
        } else if(c == ';') {
             ttype = TOK_SEMICOLON;
        } else if(c == '(') {
             ttype = TOK_BR_OPEN;
        } else if(c == ')') {
             ttype = TOK_BR_CLOSE;
        } else if(c == '{') {
             ttype = TOK_CURLY_BR_OPEN;
        } else if(c == '}') {
             ttype = TOK_CURLY_BR_CLOSE;
        } else if(c == '[') {
             ttype = TOK_SQ_BR_OPEN;
        } else if(c == ']') {
             ttype = TOK_SQ_BR_CLOSE;
        } else {
            if(PRINT_WARNINGS) printf("####WARNING####: unknown sign %c\n", c);
            automat->error();
        }

        automat->mkToken(ttype, c, shown_row, shown_col);//keep in state!
    } else if(c == EOF) {
        automat->stop();
    } else {
        if(PRINT_WARNINGS) printf("####WARNING####: unknown sign %c\n", c);
        automat->error();
    }
}

/**
* This class represents the special sign order <!> (first) state
*/
void State11::read(char c, IAutomat* automat)
{
    if(c == '!') {
        automat->setCurrentState(State12::makeState());
    } else if(Helper::isAlpha(c) || Helper::isNumerical(c) || Helper::isSign(c) || Helper::isSpace(c)) {//all other valid signs
        automat->mkToken(TOK_ANGLE_BR_OPEN, '<', shown_row, shown_col);// '<'-token
        if(c != '\n') automat->ungetChar(1);//dont unget when newline (because its difficult to keep the col- and row-number correct)
        automat->setCurrentState(State0::makeState());
    } else if(c == EOF) {
        automat->mkToken(TOK_ANGLE_BR_OPEN, '<', shown_row, shown_col);// '<'-token
        automat->stop();
    } else {
        if(PRINT_WARNINGS) printf("####WARNING####: unknown sign %c\n", c);
        automat->mkToken(TOK_ANGLE_BR_OPEN, '<', shown_row, shown_col);// '<'-token
        automat->error();
        automat->setCurrentState(State0::makeState());
    }
}

/**
* This class represents the special sign order <!> (second) state
*/
void State12::read(char c, IAutomat* automat)
{
    if(c == '>') {
        automat->mkToken(TOK_SPECIAL, 0, shown_row, shown_col);//ignore value!
        automat->setCurrentState(State0::makeState());
    } else if(Helper::isAlpha(c) || Helper::isNumerical(c) || Helper::isSign(c) || Helper::isSpace(c) || c == EOF) {//all other valid signs
        automat->mkToken(TOK_ANGLE_BR_OPEN, '<', shown_row, shown_col);
        if(c != '\n') automat->ungetChar(2);//dont unget when newline (because its difficult to keep the col- and row-number correct)
        else automat->ungetChar(1);//unget only the '!' sign
        automat->setCurrentState(State0::makeState());
    } else {
        if(PRINT_WARNINGS) printf("####WARNING####: unknown sign %c\n", c);
        automat->mkToken(TOK_ANGLE_BR_OPEN, '<', shown_row, shown_col);
        automat->error();
        automat->setCurrentState(State0::makeState());
    }
}

/**
* This class represents the integer state
*/
void State2::read(char c, IAutomat* automat)
{
    if(Helper::isNumerical(c)) {
        automat->putCharForInteger(c);
    } else if(Helper::isAlpha(c) || Helper::isSign(c)|| Helper::isSpace(c)) {//all other valid signs
        automat->mkToken(TOK_INTEGER, 0, shown_row, shown_col);//ignore value!
        if(c != '\n') automat->ungetChar(1);//dont unget when newline (because its difficult to keep the col- and row-number correct)
        automat->setCurrentState(State0::makeState());
    } else if(c == EOF) {
        automat->mkToken(TOK_INTEGER, 0, shown_row, shown_col);//ignore value!
        automat->stop();
    } else {
        if(PRINT_WARNINGS) printf("####WARNING####: unknown sign %c\n", c);
        automat->mkToken(TOK_INTEGER, 0, shown_row, shown_col);//ignore value!
        automat->error();
        automat->setCurrentState(State0::makeState());
    }
}

/**
* This class represents the letter state
*/
void State3::read(char c, IAutomat* automat)
{
    if(Helper::isAlpha(c) || Helper::isNumerical(c)) {
        automat->putCharForIdentifier(c);
    } else if(Helper::isSign(c)|| Helper::isSpace(c)) {//all other valid signs
        automat->mkToken(TOK_IDENTIFIER, 0, shown_row, shown_col);//ignore value!
        if(c != '\n') automat->ungetChar(1);//dont unget when newline (because its difficult to keep the col- and row-number correct)
        automat->setCurrentState(State0::makeState());
    } else if(c == EOF) {
        automat->mkToken(TOK_IDENTIFIER, 0, shown_row, shown_col);//ignore value!
        automat->stop();
    } else {
        if(PRINT_WARNINGS) printf("####WARNING####: unknown sign %c\n", c);
        automat->mkToken(TOK_IDENTIFIER, 0, shown_row, shown_col);//ignore value!
        automat->error();
        automat->setCurrentState(State0::makeState());
    }
}

/**
* This class represents the special sign order <!> (first) state
*/
void State41::read(char c, IAutomat* automat)
{
    if(c == '*') {
        //automat->mkToken(TOK_COMMENT_OPEN, 0, shown_row, shown_col);//ignore value!
        automat->setCurrentState(State42::makeState());
    } else if(Helper::isAlpha(c) || Helper::isNumerical(c) || Helper::isSign(c) || Helper::isSpace(c)) {//all other valid signs
        automat->mkToken(TOK_SLASH, '/', shown_row, shown_col);
        automat->ungetChar(1);
        automat->setCurrentState(State0::makeState());
    } else if(c == EOF) {
        automat->mkToken(TOK_SLASH, '/', shown_row, shown_col);
        automat->stop();
    } else {
        if(PRINT_WARNINGS) printf("####WARNING####: unknown sign %c\n", c);
        automat->mkToken(TOK_SLASH, '/', shown_row, shown_col);
        automat->error();
        automat->setCurrentState(State0::makeState());
    }
}


/**
* This class represents the special sign order <!> (second) state
*/
void State42::read(char c, IAutomat* automat)
{
    if(c == '*') {
        automat->setCurrentState(State43::makeState());
    } else if(c == EOF) {
        //do nothing else
        automat->stop();
    } else {//all other signs, even invalid (not within alphabet Z)
        //do nothing, keep on reading (and discard signs)
        //automat->error(); is not possible!!
    }
}


/**
* This class represents the special sign order <!> (third and last) state
*/
void State43::read(char c, IAutomat* automat)
{
    if(c == '*') {
        //do nothing, keep on reading (and discard signs)
    } else if(c == '/') {
        //shown_row = automat->getRow();
        //shown_col = automat->getCol();
        //automat->mkToken(TOK_COMMENT_CLOSE, 0, shown_row, shown_col);//ignore value!
        automat->setCurrentState(State0::makeState());
    } else if(c == EOF) {
        //do nothing else
        automat->stop();
    } else {//all other signs, even invalid (not within alphabet Z)
        automat->setCurrentState(State42::makeState());
        //automat->error(); is not possible!!
    }
}

//decl of static
IState* State0::state = NULL;
IState* State1::state = NULL;
IState* State11::state = NULL;
IState* State12::state = NULL;
IState* State2::state = NULL;
IState* State3::state = NULL;
IState* State41::state = NULL;
IState* State42::state = NULL;
IState* State43::state = NULL;

State0::State0(void){}
State0::~State0(void){}
State11::State11(void){}
State11::~State11(void){}
State12::State12(void){}
State12::~State12(void){}
State2::State2(void){}
State2::~State2(void){}
State3::State3(void){}
State3::~State3(void){}
State41::State41(void){}
State41::~State41(void){}
State42::State42(void){}
State42::~State42(void){}
State43::State43(void){}
State43::~State43(void){}

IState* State0::makeState()
{
    if(state == NULL)
        state = new State0();
    return State0::state;
}

IState* State11::makeState()
{
    if(state == NULL)
        state = new State11();
    return State11::state;
}


IState* State12::makeState()
{
    if(state == NULL)
        state = new State12();
    return State12::state;
}


IState* State2::makeState()
{
    if(state == NULL)
        state = new State2();
    return State2::state;
}

IState* State3::makeState()
{
    if(state == NULL)
        state = new State3();
    return State3::state;
}


IState* State41::makeState()
{
    if(state == NULL)
        state = new State41();
    return State41::state;
}

IState* State42::makeState()
{
    if(state == NULL)
        state = new State42();
    return State42::state;
}

IState* State43::makeState()
{
    if(state == NULL)
        state = new State43();
    return State43::state;
}

